import java.util.ArrayList;
// ATM.java
// Represents an automated teller machine

public class ATM {
	private boolean userAuthenticated; // whether user is authenticated
	private int currentClientNumber; // current user's client number
	private int currentAccountNumber; // current user's account number
	private int currentAdminID; // current admin's ID number
	private Screen screen; // ATM's screen
	private Keypad keypad; // ATM's keypad
	private CashDispenser cashDispenser; // ATM's cash dispenser
	private DepositSlot depositSlot; // ATM's deposit slot
	private BankDatabase bankDatabase; // account information database
	private boolean adminAuthenticated; // whether admin is authenticated

	// constants corresponding to main menu options and admin menu options
	private static final int BALANCE_INQUIRY = 1;
	private static final int WITHDRAWAL = 2;
	private static final int DEPOSIT = 3;
	private static final int EXIT = 4;
	private static final int CREATE_CUSTOMER = 1;
	private static final int DELETE_CUSTOMER = 2;
	private static final int VIEW_CUSTOMER = 3;

	// no-argument ATM constructor initializes instance variables
	public ATM() {
		currentAccountNumber = 0;
		userAuthenticated = false; // user is not authenticated to start
		currentClientNumber = 0; // no current account number to start
		currentAdminID = 0; // currentAdminID starts with value 0
		screen = new Screen(); // create screen
		keypad = new Keypad(); // create keypad
		cashDispenser = new CashDispenser(); // create cash dispenser
		depositSlot = new DepositSlot(); // create deposit slot
		bankDatabase = new BankDatabase(); // create acct info database
	} // end no-argument ATM constructor

	// start ATM
	public void run() {

		// welcome and authenticate user; perform transactions
		while (true) {
			// loop while user is not yet authenticated
			while (!userAuthenticated) {
				screen.printTop();
				screen.printMessage("Welcome!");
				screen.printBot();
				authenticateUser(); // authenticate user
			} // end while

			// checks whether the adminPIN is correct
			if (currentAdminID == 10000) {
				performAdminTransactions();
			} else {
				performTransactions(); // user is now authenticated
			}
			userAuthenticated = false; // reset before next ATM session
			adminAuthenticated = false; // reset before next ATM session
			currentClientNumber = 0; // reset before next ATM session
			currentAdminID = 0; // reset before next ATM session
			screen.printBlank();
			screen.printMessage("Thank you! Goodbye!");
			screen.printBot();
		} // end while
	} // end method run

	// attempts to authenticate user against database
	private void authenticateUser() {
		screen.displayMessage("\nPlease enter your client number: ");
		int clientNumber = keypad.getInput();// input account number
		int adminID = clientNumber;
		screen.displayMessage("\nEnter your PIN: "); // prompt for PIN
		int pin = keypad.getInput(); // input PIN
		int adminPIN = pin;

		// set userAuthenticated to boolean value returned by database
		userAuthenticated = bankDatabase.authenticateUser(clientNumber, pin);
		if (!userAuthenticated) {
			userAuthenticated = bankDatabase.authenticateAdmin(adminID,
					adminPIN);
		} // end if 

		// check whether authentication succeeded
		if (userAuthenticated) {
			currentAdminID = adminID; // save admin's AdminID #
			currentClientNumber = clientNumber; // save user's clientNumber #

		} // end if
		else { // if user or admin enters wrong ClientNumber/adminID or pin
			screen.printTop();
			screen.printMessage("Invalid account number or PIN.");
			screen.printMessage("Please try again.");
			screen.printBot();
		} // end else
	} // end method authenticateUser

	// display the main menu and perform transactions
	private void performTransactions() {
		// local variable to store transaction currently being processed
		Transaction currentTransaction = null;

		boolean userExited = false; // user has not chosen to exit

		// loop while user has not chosen option to exit system
		while (!userExited) {
			displayMainMenu();
			// show main menu and get user selection
			int AccountSelection = displayAccountMenu();

			// decide how to proceed based on user's menu selection
			switch (AccountSelection) {
			// user chose to perform one of three transaction types
			case BALANCE_INQUIRY:
			case WITHDRAWAL:
			case DEPOSIT:

				// initialize as new object of chosen type
				currentTransaction = createTransaction(AccountSelection);

				currentTransaction.execute(); // execute transaction
				break;
			case EXIT: // user chose to terminate session
				screen.printTop();
				screen.printMessage("Exiting the system...");
				userExited = true; // this ATM session should end
				break;
			default: // user did not enter an integer from 1-4
				screen.printTop();
				screen.printMessage("You did not enter a valid selection.");
				screen.printMessage("Try again.");
				screen.printBot();
				break;
			} // end switch
		} // end while
	} // end method performTransactions

	private void performAdminTransactions() {
		// local variable to store transaction currently being processed
		Transaction currentTransaction = null;

		boolean userExited = false; // user has not chosen to exit

		// loop while admin has not chosen option to exit system
		while (!userExited) {
			// show admin menu and get admin selection
			int adminSelection = displayAdminMenu();

			// decide how to proceed based on admin's menu selection
			switch (adminSelection) {
			// admin chose to perform one of three transaction types
			case CREATE_CUSTOMER:
				// Prompts the admin to enter all the information on the
				// customer - First Name, Last name, etc.
				screen.printTop();
				screen.printMessage("Enter customer first name: ");
				screen.printBot();
				String setFirstName = keypad.getInputString();
				screen.printTop();
				screen.printMessage("Enter customer last name: ");
				screen.printBot();
				String setLastName = keypad.getInputString();
				screen.printTop();
				screen.printMessage("Enter customer CPR/CVR-number: ");
				screen.printBot();
				String setCPR = keypad.getInputString();
				screen.printTop();
				screen.printMessage("Enter customer type (private/business): ");
				screen.printBot();
				String setCustomerType = keypad.getInputString();
				screen.printTop();
				screen.printMessage("Enter customer city: ");
				screen.printBot();
				String setCity = keypad.getInputString();
				screen.printTop();
				screen.printMessage("Enter customer zipcode: ");
				screen.printBot();
				int setZip = keypad.getInput();
				screen.printTop();
				screen.printMessage("Enter customer number: ");
				screen.printBot();
				int setClientNumber = keypad.getInput();
				screen.printTop();
				screen.printMessage("Enter customer PIN: ");
				screen.printBot();
				int setPIN = keypad.getInput();
				// saves all the inputs and adds the new customer with his
				// information into the customerList in bankDatabase
			
				//calls method addCustomer to add new customers into the arrayList
				bankDatabase.addCustomer(new Customer(setFirstName,
						setLastName, setCPR, setCustomerType, setCity, setZip,
						setClientNumber, setPIN));

				break;
			// displays all the customers and asks for input and deletes the
			// customer with the method removeCustomer
			case DELETE_CUSTOMER:
				screen.printTop();
				screen.printMessage("Name, CPR, City, Zip, Client number, PIN");
				screen.printBlank();
				screen.displayMessage(bankDatabase.viewCustomer());
				screen.printBot();
				screen.displayMessageLine("Type the number of the client you want to delete:");
				int i = 0;
				while (i == 0) { // initiates the while-loop that runs until i>0
					int clNumber = keypad.getInput(); // gets input from the
														// keypar
					try { // tries whether the following code works without
							// exceptions
						bankDatabase.removeCustomer(clNumber); // uses the
																// method
																// removeCustomer
																// to remove a
																// customer from
																// the
																// bankDatabase
						i = 1;

					} catch (Exception e) { // catches the error and displays an
											// message
						screen.printTop();
						screen.printMessage("Invalid selection, try again : ");
						screen.printBot();
					} // end catch
				} // end while loop

				screen.printTop();
				screen.printMessage("Customer deleted!");
				screen.printBot();
				break;

			case VIEW_CUSTOMER:
				screen.printTop();
				screen.printMessage("Name, CPR, City, Zip, Client number, PIN");
				screen.printBlank();
				screen.displayMessage(bankDatabase.viewCustomer());
				screen.printBot();

				// // initialize as new object of chosen type
				// currentTransaction = createTransaction(adminSelection);
				// currentTransaction.execute(); // execute transaction
				break;
			case EXIT: // user chose to terminate session
				screen.printTop();
				screen.printMessage("Exiting the system...");
				userExited = true; // this ATM session should end
				break;
			default: // user did not enter an integer from 1-4
				screen.printTop();
				screen.printMessage("You did not enter a valid selection. Try again.");
				screen.printBot();
				break;
			} // end switch
		} // end while
	} // end method performTransactions

	// method for displaying main menu
	private void displayMainMenu() {
		// gets the customer with the currentClientNumber
		Customer cust = bankDatabase.getCustomer(currentClientNumber);
		screen.printTop();
		screen.printMessage("Welcome back, " // shows the firstName of the
												// client
				+ bankDatabase.getFirstName(currentClientNumber) + "!");
		screen.printBlank();
		screen.printMessage("Accounts:");
		ArrayList<Account> accountList = cust.getAccountList();
		int accountNumber = 1;
		for (Account currentAccount : accountList) {
			screen.printMessage(accountNumber + ". "
					+ currentAccount.getAccountNumber());
			accountNumber++;
			// return current account if match found
		} // end for
		screen.printBot();
		screen.displayMessage("Choose account: "); // prompts user to choose
													// account (1-3)

		// initiates while loop that catches out of bounds exceptions
		// if the user enters and number out of the array
		int i = 0;
		while (i == 0) { // initializes an try/catch within a while loop
							// to catch out of bounds exceptions
			int account = keypad.getInput();
			try { // tries whether the following code works without errors
				currentAccountNumber = accountList.get(account - 1)
						.getAccountNumber(); // runs through the accountlist and
												// finds the correct account
				i = 1;

			} catch (Exception e) { // catches the errors and displays a message
				screen.printTop();
				screen.printMessage("Invalid selection, try again (1-3): ");
				screen.printBot();
			} // end catch
		} // end while loop
	} // end method displayMainMenu

	// display the main menu and return an input selection
	private int displayAccountMenu() {
		screen.printTop();
		screen.printMessage("Main menu:");
		screen.printBlank();
		screen.printMessage("1 - View my balance");
		screen.printMessage("2 - Withdraw cash");
		screen.printMessage("3 - Deposit funds");
		screen.printMessage("4 - Exit");
		screen.printBot();
		screen.displayMessage("Enter a choice: \n");
		return keypad.getInput(); // return user's selection
	} // end method displayMainMenu

	// display the main menu and return an input selection
	private int displayAdminMenu() {
		screen.printTop();
		screen.printMessage("Admin menu:");
		screen.printBlank();
		screen.printMessage("1 - Create New Customer");
		screen.printMessage("2 - Delete Customer");
		screen.printMessage("3 - View Customers");
		screen.printMessage("4 - Exit");
		screen.printBot();
		screen.displayMessage("Enter a choice: \n");
		return keypad.getInput(); // return admin's selection
	} // end method displayAdminMenu

	// return object of specified Transaction subclass
	private Transaction createTransaction(int type) {
		Transaction temp = null; // temporary Transaction variable

		// determine which type of Transaction to create
		switch (type) {
		case BALANCE_INQUIRY: // create new BalanceInquiry transaction
			temp = new BalanceInquiry(currentClientNumber,
					currentAccountNumber, screen, bankDatabase);
			break;
		case WITHDRAWAL: // create new Withdrawal transaction
			temp = new Withdrawal(currentClientNumber, currentAccountNumber,
					screen, bankDatabase, keypad, cashDispenser);
			break;
		case DEPOSIT: // create new Deposit transaction
			temp = new Deposit(currentClientNumber, currentAccountNumber,
					screen, bankDatabase, keypad, depositSlot);
			break;
		} // end switch

		return temp; // return the newly created object
	} // end method createTransaction

} // end class ATM

/**************************************************************************
 * (C) Copyright 1992-2012 by Deitel & Associates, Inc. and * Pearson Education,
 * Inc. All Rights Reserved. * * DISCLAIMER: The authors and publisher of this
 * book have used their * best efforts in preparing the book. These efforts
 * include the * development, research, and testing of the theories and programs
 * * to determine their effectiveness. The authors and publisher make * no
 * warranty of any kind, expressed or implied, with regard to these * programs
 * or to the documentation contained in these books. The authors * and publisher
 * shall not be liable in any event for incidental or * consequential damages in
 * connection with, or arising out of, the * furnishing, performance, or use of
 * these programs. *
 *************************************************************************/
